/* Copyright (c) 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.orkut.client.api.samples.greetings.client.ui;

import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.google.orkut.client.api.samples.greetings.client.DataModel;
import com.google.orkut.client.api.samples.greetings.client.GreetingsCallbackWrapper;
import com.google.orkut.client.api.samples.greetings.client.GreetingsMessages;
import com.google.orkut.client.api.samples.greetings.client.DataModel.DataModelUpdateCallback;
import com.google.orkut.client.api.samples.greetings.client.selector.ItemSection;
import com.google.orkut.client.api.samples.greetings.client.services.UserInfo;
import com.google.orkut.client.api.samples.greetings.client.services.UserServiceAsync;

import java.util.ArrayList;

/**
 * A UI widget that lists friends and allows the user to select multiple friends.
 *
 * @author Shishir Birmiwal
 */
public class FriendSelector extends Composite
implements DataModelUpdateCallback, AsyncCallback<ArrayList<UserInfo>> {
  private static FriendSelectorUiBinder uiBinder = GWT.create(FriendSelectorUiBinder.class);

  interface FriendSelectorUiBinder extends UiBinder<Widget, FriendSelector> {
  }

  @UiField(provided = true)
  UserSelector selected;

  @UiField(provided = true)
  UserSelector unselected;

  @UiField
  ItemSection itemSection;

  private final DataModel dataModel;
  private final UserServiceAsync userService;
  private final String postToken;
  private final GreetingsMessages msgs;

  private final ArrayList<UserInfo> selectedFriends;
  private final ArrayList<UserInfo> unselectedFriends;

  private final GreetingsCallbackWrapper cbWrapper;

  @Inject
  public FriendSelector(
      @Named("postToken") String postToken,
      GreetingsMessages msgs,
      GreetingsCallbackWrapper cbWrapper,
      UserServiceAsync userService,
      DataModel dataModel,
      UserSelector selected,
      UserSelector unselected) {
    this.postToken = postToken;
    this.msgs = msgs;
    this.cbWrapper = cbWrapper;
    this.userService = userService;
    this.dataModel = dataModel;
    this.selected = selected;
    this.unselected = unselected;
    selectedFriends = new ArrayList<UserInfo>();
    unselectedFriends = new ArrayList<UserInfo>();
    setupCallbacks(dataModel);
    initWidget(uiBinder.createAndBindUi(this));
  }

  public void setTitle(String title) {
    itemSection.setTitle(title);
  }

  private void setupCallbacks(DataModel dataModel) {
    dataModel.registerCallback(this);
    selected.setUserSelectedCallback(new UserSelector.UserSelectedCallback() {
      @Override
      public void userSelected(UserInfo user) {
        selectedFriends.remove(user);
        unselectedFriends.add(user);
        updateItems();
      }
    });
    unselected.setUserSelectedCallback(new UserSelector.UserSelectedCallback() {
      @Override
      public void userSelected(UserInfo user) {
        unselectedFriends.remove(user);
        selectedFriends.add(user);
        updateItems();
      }
    });
  }

  private void updateItems() {
    selected.updateItems(selectedFriends);
    unselected.updateItems(unselectedFriends);
    dataModel.updateSelectedRecipients(selectedFriends);
  }

  @Override
  public void update(DataModel data, Type type) {
    if (Type.SELECTED_USER.equals(type)) {
      userService.getFriendsOf(postToken, data.selectedUser.id, cbWrapper.wrap(this));
    }
    if (!Type.USER_INFO_TABLE.equals(type)) {
      return;
    }
    // update list of friends
    for (UserInfo user : data.userInfo.values()) {
      if (selectedFriends.contains(user) || user.id.equals(dataModel.selectedUser.id)) {
        continue;
      }
      unselectedFriends.add(user);
    }

    for (UserInfo user : selectedFriends) {
      if (!data.userInfo.containsValue(user)) {
        selectedFriends.remove(user);
      }
    }
    updateItems();
  }

  @Override
  public void onFailure(Throwable caught) {
    Window.alert(msgs.errorFetchingFriends());
  }

  @Override
  public void onSuccess(ArrayList<UserInfo> users) {
    dataModel.addUsers(users);
  }

  public ArrayList<UserInfo> getSelectedFriends() {
    return selectedFriends;
  }

  public void expand() {
    itemSection.expand();
  }

  public void collapse() {
    itemSection.collapse();
  }

  public void reset() {
    unselectedFriends.addAll(selectedFriends);
    selectedFriends.clear();
    updateItems();
  }
}
